package Manager

import (
	"backend/Remote"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func GetMD5sum(filepath string) (string, error) {
	file, err := os.Open(filepath)
	if err != nil {
		log.Println(err)
		return "", err
	}

	hash := md5.New()
	_, err = io.Copy(hash, file)
	if err != nil {
		log.Println(err)
		return "", err
	}

	sum := hash.Sum(nil)
	value := hex.EncodeToString(sum)
	return value, nil
}

func getLocalFiles(localFolder string) []string {
	var localFiles []string
	err := filepath.Walk(localFolder, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			fmt.Println("err:", err)
			return err
		}

		// 获取相对路径
		relPath, err := filepath.Rel(localFolder, path)
		if err != nil {
			return err
		}

		linuxPath := strings.ReplaceAll(relPath, `\`, "/")

		// 如果是文件，写入文件内容
		//localFiles = append(localFiles, linuxPath)
		if linuxPath != "." {
			localFiles = append(localFiles, linuxPath)
		}
		return nil
	})

	if err != nil {
		return nil
	} else {
		return localFiles
	}
}

func getLocalMD5sum(localFolder string) map[string]string {
	md5sumData := make(map[string]string)

	err := filepath.Walk(localFolder, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			log.Println("func err:", err)
			return err
		}

		if path == localFolder {
			return nil
		}

		// 获取相对路径
		relPath, err := filepath.Rel(localFolder, path)
		if err != nil {
			return err
		}

		// 调整为linux格式的路径
		linuxPath := strings.ReplaceAll(relPath, `\`, "/")
		// 文件夹
		if info.IsDir() {
			md5sumData[linuxPath] = "dir"
			return nil
		}

		sum, err := GetMD5sum(path)
		if err != nil {
			log.Println("md5Sum err:", err)
			return err
		}

		md5sumData[linuxPath] = sum

		return nil
	})
	if err != nil {
		log.Fatal("filePath.walk err:", err)
	}

	return md5sumData
}

func md5WorkerByLocal(i int, localFiles []string, done chan bool) {
	fmt.Printf("【%s】远程服务器开始收集文件的MD5sum值...\n", Remote.Hosts[i].IP)
	Remote.Hosts[i].Connect()
	defer Remote.Hosts[i].Clear()
	Remote.Hosts[i].GetMD5sumByLocalFiles(localFiles)
	done <- true
	fmt.Printf("【%s】远程服务器的MD5sum收集完成\n", Remote.Hosts[i].IP)
}

func md5Worker(i int, done chan bool) {
	fmt.Printf("【%s】远程服务器开始收集文件的MD5sum值...\n", Remote.Hosts[i].IP)
	Remote.Hosts[i].Connect()
	defer Remote.Hosts[i].Clear()
	Remote.Hosts[i].GetMD5sum()
	done <- true
	fmt.Printf("【%s】远程服务器的MD5sum收集完成\n", Remote.Hosts[i].IP)
}

func getRemoteMD5sum() {
	done := make(chan bool)

	for i := range Remote.Hosts {
		go md5Worker(i, done)
	}

	num := len(Remote.Hosts)
	for i := 0; i < num; i++ {
		<-done
	}
}

func getRemoteMD5sumByLocalFileName(localFiles []string) {
	done := make(chan bool)
	for i := range Remote.Hosts {
		go md5WorkerByLocal(i, localFiles, done)
	}
	m := len(Remote.Hosts)
	for i := 0; i < m; i++ {
		<-done
	}
}

func rsyncWorker(i int, done chan bool, localFolder string, localMD5sumData map[string]string) {
	Remote.Hosts[i].Connect()
	defer Remote.Hosts[i].Clear()

	Remote.Hosts[i].CompareMD5sum(localMD5sumData)

	Remote.Hosts[i].Rsync(localFolder)
	done <- true
}

func rsyncToHosts(localFolder string) {
	localMD5sumData := getLocalMD5sum(localFolder)

	done := make(chan bool)
	for i := range Remote.Hosts {
		go rsyncWorker(i, done, localFolder, localMD5sumData)
	}

	num := len(Remote.Hosts)
	for i := 0; i < num; i++ {
		<-done
	}
}
